#include "StdAfx.h"
#include "Enemy.h"
#include "Helper.h"
#include "Time.h"

using namespace std;

// class Bullet
#pragma region Bullet

Bullet::Bullet(IDirect3DDevice9 *pd3dDevice, D3DXVECTOR3 *pVecPosition, D3DXVECTOR3 *pDirection)
	:m_pd3dDevice(pd3dDevice),
	m_fRadius(0.2f),
	m_fSpeed(100.0f),
	m_fDistance(0.0f),
	m_bAlive(true)
{
	D3DXCreateSphere(m_pd3dDevice, m_fRadius, 20, 20, &m_pMesh, NULL);
	DrawMeshColor(m_pd3dDevice, &m_pMesh, 0.0f, 0.3f, 0.8f, 0.7f);

	D3DXMatrixTranslation(&m_matPosition, pVecPosition->x, pVecPosition->y, pVecPosition->z);

	m_vecDirection = *pDirection;
	D3DXVec3Normalize(&m_vecDirection, &m_vecDirection);
}

Bullet::~Bullet()
{
	SAFE_RELEASE(m_pMesh);
}

void Bullet::Update()
{
	D3DXMATRIX matMoveFrame;
	D3DXVECTOR3 vecMove = m_vecDirection * (float)Time::Delta() * m_fSpeed;

	D3DXMatrixTranslation(&matMoveFrame, vecMove.x, vecMove.y, vecMove.z);

	m_matPosition *= matMoveFrame;
	m_fDistance += D3DXVec3Length(&vecMove);

	m_pd3dDevice->SetTransform(D3DTS_WORLD, &m_matPosition);
	m_pMesh->DrawSubset(0);
}

const D3DXVECTOR3 &Bullet::Position()
{
	D3DXVec3TransformCoord(&m_vecPosition, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &m_matPosition);

	return m_vecPosition;
}

float Bullet::Distance() const
{
	return m_fDistance;
}

float Bullet::Radius() const
{
	return m_fRadius;
}

void Bullet::Kill()
{
	m_bAlive = false;
}

bool Bullet::Alive() const
{
	return m_bAlive;
}

#pragma endregion Bullet

// class Gun
#pragma region Gun

list<Bullet *> Gun::sm_vecBullet;
int Gun::sm_nInstanceCount = 0;

Gun::Gun(IDirect3DDevice9 *pd3dDevice, float fRange)
	:m_pd3dDevice(pd3dDevice),
	m_fRange(fRange)
{
	++sm_nInstanceCount;
}

Gun::~Gun()
{
	--sm_nInstanceCount;

	if (sm_nInstanceCount <= 0)
	{
		for (list<Bullet *>::iterator it = sm_vecBullet.begin(); it != sm_vecBullet.end();)
		{
			delete *it;
			it = sm_vecBullet.erase(it);
		}
	}
};

void Gun::Fire(D3DXVECTOR3 *pVecPosition, D3DXVECTOR3 *pVecDirection)
{
	sm_vecBullet.push_back(new Bullet(m_pd3dDevice, pVecPosition, pVecDirection));
}

void Gun::Update()
{
	for (list<Bullet *>::iterator it = sm_vecBullet.begin(); it != sm_vecBullet.end();)
	{
		(*it)->Update();
		
		if (!(*it)->Alive() || (*it)->Distance() > m_fRange)
		{
			delete *it;
			it = sm_vecBullet.erase(it);
		}
		else
		{
			++it;
		}
	}
}

list<Bullet *> &Gun::Bullets()
{
	return sm_vecBullet;
}

#pragma endregion Gun

// class Enemy
#pragma region Enemy

Enemy::Enemy(IDirect3DDevice9 *pd3dDevice, D3DXVECTOR3 *pVecFrom, D3DXVECTOR3 *pVecTo, float fSpeed)
	:m_pd3dDevice(pd3dDevice),
	m_vecFrom(*pVecFrom),
	m_vecTo(*pVecTo),
	m_fRadius(1.0f),
	m_fSpeed(fSpeed),
	m_fDistance(0.0f),
	m_bAlive(true)
{
	D3DXCreateSphere(m_pd3dDevice, m_fRadius, 20, 20, &m_pMesh, NULL);
	DrawMeshColor(m_pd3dDevice, &m_pMesh, 1.0f, 0.0f, 0.0f, 1.0f);
	D3DXMatrixTranslation(&m_matTransform, pVecFrom->x, pVecFrom->y, pVecFrom->z);
}

Enemy::~Enemy()
{
	SAFE_RELEASE(m_pMesh);
}

void Enemy::Update()
{
	D3DXMATRIX matMoveFrame;
	D3DXVECTOR3 vecDirection = m_vecTo - m_vecFrom;

	D3DXVec3Normalize(&vecDirection, &vecDirection);

	D3DXVECTOR3 vecMove = vecDirection * (float)Time::Delta() * m_fSpeed;

	D3DXMatrixTranslation(&matMoveFrame, vecMove.x, vecMove.y, vecMove.z);

	m_matTransform *= matMoveFrame;
	m_fDistance += D3DXVec3Length(&vecMove);

	m_pd3dDevice->SetTransform(D3DTS_WORLD, &m_matTransform);
	m_pMesh->DrawSubset(0);
}

const D3DXVECTOR3 &Enemy::Position()
{
	D3DXVec3TransformCoord(&m_vecPosition, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &m_matTransform);

	return m_vecPosition;
}

float Enemy::Distance() const
{
	return m_fDistance;
}

float Enemy::Radius() const
{
	return m_fRadius;
}

void Enemy::Kill()
{
	m_bAlive = false;
}

bool Enemy::Alive() const
{
	return m_bAlive;
}

#pragma endregion Enemy

// class Barrack
#pragma region Barrack

list<Enemy *> Barrack::sm_vecEnemy;
int Barrack::sm_nInstanceCount = 0;

Barrack::Barrack(IDirect3DDevice9 *pd3dDevice, float fMaxPath)
	:m_pd3dDevice(pd3dDevice),
	m_fMaxPath(fMaxPath)
{
	++sm_nInstanceCount;
}


Barrack::~Barrack(void)
{
	--sm_nInstanceCount;

	if (sm_nInstanceCount <= 0)
	{
		for (list<Enemy *>::iterator it = sm_vecEnemy.begin(); it != sm_vecEnemy.end();)
		{
			delete *it;
			it = sm_vecEnemy.erase(it);
		}
	}
}

void Barrack::Attack(D3DXVECTOR3 *vecFrom, D3DXVECTOR3 *vecTo)
{
	float fRandomSpeed = (rand() % 100) / 60.0f + 0.7f;
	sm_vecEnemy.push_back(new Enemy(m_pd3dDevice, vecFrom, vecTo, fRandomSpeed));
}

void Barrack::Update()
{
	for (list<Enemy *>::iterator it = sm_vecEnemy.begin(); it != sm_vecEnemy.end();)
	{
		(*it)->Update();

		if (!(*it)->Alive() || (*it)->Distance() > m_fMaxPath)
		{
			delete *it;
			it = sm_vecEnemy.erase(it);
		}
		else
		{
			++it;
		}
	}
}

list<Enemy *> &Barrack::Enemies()
{
	return sm_vecEnemy;
}

#pragma endregion Barrack
